using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
using System.Xml;
using System.Xml.XPath;

namespace SiliverlightJavascriptIntelli
{
    public static class ReferenceAnalyzer
    {
        public const string prefix_property = "p";
        public const string prefix_method = "m";
        public const string prefix_event = "e";
        public const string prefix_class = "o";
        public const string spacer = "_";

        public static readonly List<string> RemoveFromString = new List<string>();
        private static string referencePath = "~/../../../reference/";
        private static string extension = ".htm";
        private static string xmlHeader = @"<?xml version=""1.0"" encoding=""utf-8"" ?> ";
        public static readonly List<Regex> RemoveFromStringRegex = new List<Regex>();
        private static RegexOptions options = RegexOptions.Singleline | RegexOptions.IgnoreCase;


        static ReferenceAnalyzer()
        {
            RemoveFromString.Add(@"document.write("" <table width=\""100%\"" bgcolor=\""#e1e1e1\""cellspacing=\""2\"" cellpadding=\""0\"" style=\""border-collapse: collapse; font-family: sans-serif; font-size: 14px; color: #000000; text-decoration: none;  \""> <tr> <td align=\""center\"" style=\""border-bottom: 2px solid gray\"" > <br>Click <a href=\""../../index.html?page=source%2freference%2fo_textwrapping.htm\"">here</a> to show toolbars of the Web Online Help System: <a href=\""../../index.html?page=source%2freference%2fo_textwrapping.htm\"">show toolbars</a><br></td></tr></table><br> "");");
            RemoveFromString.Add(@"&nbsp;");

            RemoveFromStringRegex.Add(new Regex(@"xmlns[^( )]*?"".*?""", options));
            RemoveFromStringRegex.Add(new Regex(@"\<script([^>])*\>.*?\<\/script\>", options));
            RemoveFromStringRegex.Add(new Regex(@"\<\!DOCTYPE.*?\>", options));


        }

        public static string GetDescrptionForClass(string className)
        {
            return ReturnXpathQueryResultOnHtmlFromFile(GetFileNameForClass(className), "//div[@id=\"mainBody\"]/p");
        }


        public static string GetDescrptionForProperty(string className, string propertyName)
        {
            string xpath = "//div[@id=\"mainBody\"]/p";
            string[] PossiableDescription = new string[]
                {
                    ReturnXpathQueryResultOnHtmlFromFile(GetLongFileNameForProperty(className, propertyName), xpath),
                    ReturnXpathQueryResultOnHtmlFromFile(GetShortFileNameForProperty(propertyName), xpath),
                    ReturnXpathQueryResultOnHtmlFromFile(GetInheritedLongFileNameForProperty(propertyName), xpath),
                };

            return ReturnFirstNonEmpty(PossiableDescription);
        }



        private static string ReturnFirstNonEmpty(string[] ReturnValues)
        {
            foreach (string curReturnValue in ReturnValues)
            {
                if (!string.IsNullOrEmpty(curReturnValue))
                    return curReturnValue;
            }

            return null;
        }

        private static string GetLongFileNameForProperty(string className, object propertyName)
        {
            return  prefix_property + spacer + className + spacer + propertyName + extension;
        }

        private static string GetInheritedLongFileNameForProperty(object propertyName)
        {
            string possiableFileNameTemplate = prefix_property + spacer + "*" + propertyName + extension;

            foreach (string curFileName in Directory.GetFiles(referencePath, possiableFileNameTemplate))
            {
                return Path.GetFileNameWithoutExtension(curFileName);
            }

            return null;

        }

        private static string GetShortFileNameForProperty(object propertyName)
        {
            return prefix_property + spacer + propertyName;
        }

        public static string GetDescrptionForMethod(string methodName)
        {
            return ReturnXpathQueryResultOnHtmlFromFile(GetFileNameForMethod(methodName), "//div[@id=\"mainBody\"]/p");
        }

        private static string GetFileNameForMethod(string methodName)
        {
            string possiableFileNameTemplate = prefix_method + spacer + "*" + spacer + methodName + extension;

            foreach (string curFileName in Directory.GetFiles(referencePath, possiableFileNameTemplate))
            {
                return Path.GetFileNameWithoutExtension(curFileName);
            }

            return null;

        }

        private static string ReturnXpathQueryResultOnHtmlFromFile(string fileName, string xpath)
        {
            string filePath = BuildFilePathFor(fileName);
            if (File.Exists(filePath))
            {
                string contents = GetTextFrom(filePath);
                contents = FormatHtmlToValidXml(contents);

                string Result = GetTextFromNode(contents, xpath, fileName);
                Result = FormatFromHtmlToText(Result);

                return Result;
            }
            return null;
        }

        private static string GetTextFromNode(string contents, string xpath, string fileName)
        {
            XmlDocument doc = new XmlDocument();
            doc.LoadXml(contents);
            XmlNode result = doc.SelectSingleNode(xpath);
            if (result != null)
                return result.InnerText;
            else
                return string.Empty;

        }

        private static XmlNodeList ReturnXpathQueryResultsOnHtmlFromFile(string fileName, string xpath)
        {
            string filePath = BuildFilePathFor(fileName);
            if (File.Exists(filePath))
            {
                string contents = GetTextFrom(filePath);
                contents = FormatHtmlToValidXml(contents);

                XmlDocument doc = new XmlDocument();
                doc.LoadXml(contents);
                return doc.SelectNodes(xpath);

            }
            return null;
        }

        private static string GetTextFrom(string filePath)
        {
            return File.ReadAllText(filePath);
        }

        private static string BuildFilePathFor(string fileName)
        {
            return referencePath + fileName + extension;
        }

        private static string FormatHtmlToValidXml(string contents)
        {
            contents = xmlHeader + contents;
            foreach (string stringToRemove in RemoveFromString)
            {
                contents = contents.Replace(stringToRemove, string.Empty);
            }
            foreach (Regex regexToRemove in RemoveFromStringRegex)
            {
                contents = regexToRemove.Replace(contents, string.Empty);
            }

            return contents;
        }

        private static string GetFileNameForClass(string className)
        {
            return prefix_class + spacer + className;
        }

        private static string FormatFromHtmlToText(string result)
        {
            string ReturnValue = result;

            ReturnValue = ReturnValue.Replace("\r\n", " ");

            return ReturnValue;
        }

        public static string GetDescriptionForParam(string className, string methodName, string parameterName)
        {
            parameterName = ChangeParameterNameIfDocumentationDoesNotMatchAssembly(methodName, parameterName);

            return ReturnXpathQueryResultOnHtmlFromFile(GetFileNameForMethod(methodName),
                                                        string.Format(
                                                            "//tr[td[@class=\"parametername\"]/i[translate(text(), 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz')=\"{0}\"]]/td[@class=\"parameterdesc\"]/p",
                                                            parameterName.ToLower()));


            //   string xpath = "//div[@id=\"mainBody\"]/p";
            //   string[] PossiableDescription = new string[]
            //       {

            //           ReturnXpathQueryResultOnHtmlFromFile(GetLongFileNameForProperty(className, propertyName), xpath),
            //           ReturnXpathQueryResultOnHtmlFromFile(GetShortFileNameForProperty(propertyName), xpath),
            //           ReturnXpathQueryResultOnHtmlFromFile(GetInheritedLongFileNameForProperty(propertyName), xpath),
            //       };

            //   return ReturnFirstNonEmpty(PossiableDescription);

            //   return null;
            //   return ReturnXpathQueryResultOnHtmlFromFile(GetFileNameForMethod(methodName),
            //       string.Format("//tr[td[@class=\"parametername\"]/i[translate(text(), 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz')=\"{0}\"]]/td[@class=\"parameterdesc\"]/p", parameterName.ToLower()));

        }

        private static string ChangeParameterNameIfDocumentationDoesNotMatchAssembly(string methodName, string parameterName)
        {
            parameterName = RemoveCollectionFromParamName(parameterName);

            XmlNodeList possiableNameForParameter = GetAllParameterNamesForMethod(methodName);
            if (possiableNameForParameter != null)
            {
                parameterName = IfNameIsSlightlyIndeticaleThenChangeParameterNameToSearchFor(parameterName, possiableNameForParameter);
                parameterName = IfParameterNameInDocumetationIsTooGenericAndTheresOnlyOneThenSearchForIt(parameterName, possiableNameForParameter);

            }
            return parameterName;
        }

        private static XmlNodeList GetAllParameterNamesForMethod(string methodName)
        {
            return ReturnXpathQueryResultsOnHtmlFromFile(GetFileNameForMethod(methodName),
                                                                    "//tr/td[@class=\"parametername\"]/i");
        }

        private static string IfParameterNameInDocumetationIsTooGenericAndTheresOnlyOneThenSearchForIt(string parameterName, XmlNodeList possiableNameForParameter)
        {
            if (possiableNameForParameter.Count == 1)
                parameterName = possiableNameForParameter[0].InnerText;
            return parameterName;
        }

        private static string IfNameIsSlightlyIndeticaleThenChangeParameterNameToSearchFor(string parameterName, XmlNodeList possiableNameForParameter)
        {
            foreach (XmlNode curPossiableName in possiableNameForParameter)
            {
                if (curPossiableName.InnerText.ToLower().StartsWith(parameterName.ToLower()))
                    parameterName = curPossiableName.InnerText;
                if (parameterName.ToLower().StartsWith(curPossiableName.InnerText.ToLower()))
                    parameterName = curPossiableName.InnerText;
            }
            return parameterName;
        }

        private static string RemoveCollectionFromParamName(string parameterName)
        {
            parameterName = parameterName.Replace("Collection", "s");
            return parameterName;
        }

        public static string GetDescriptionForEvent(string className, string eventName)
        {
            string xpath = "//div[@id=\"mainBody\"]/p";
            string[] PossiableDescription = new string[]
                {
                    ReturnXpathQueryResultOnHtmlFromFile(GetLongFileNameForEvent(className, eventName), xpath),
                    ReturnXpathQueryResultOnHtmlFromFile(GetInheritedLongFileNameForEvent(eventName), xpath),
                };

            return ReturnFirstNonEmpty(PossiableDescription);
        }

        private static string GetInheritedLongFileNameForEvent(string eventName)
        {
            string possiableFileNameTemplate = prefix_event + spacer + "*" + eventName + extension;

            foreach (string curFileName in Directory.GetFiles(referencePath, possiableFileNameTemplate))
            {
                return Path.GetFileNameWithoutExtension(curFileName);
            }

            return null;
        }

        private static string GetLongFileNameForEvent(string className, string eventName)
        {
            return prefix_event + spacer + className + spacer + eventName + extension;
            
        }
    }
}
